<?php
if(!class_exists('XAnnotationClassRegister', false)){
	require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'registry'.DIRECTORY_SEPARATOR.'XAnnotationClassRegister.php');
}
if(!class_exists('XFile', false)){
	require_once(XFRAMEWORK_DIR.'/module/io/XFile.php');
}
final class XApplication{
	private static $instance = null;
	private $router = null;
	
	private function __construct() {
	
	}
	
	/** 
	 * @return XApplication
	 */	
	static function singleton() {
		if (!self::$instance) {
			self::$instance = new self;
		}
		return self::$instance;
	}
	
	public function start($route = true){
		$this->_init();
		XConfig::singleton()->load();
		//set default timezone
		$locale = XI18N::singleton()->getLocale();
		$timezone = XConfig::singleton()->get("project.i18n.{$locale}.timezone");
		if(!is_null($timezone)){
			date_default_timezone_set($timezone);
		}else{
			date_default_timezone_set("Asia/Chongqing");
		}
		//publish context started event
		XEventContext::singleton()->publish(new XContextStartedEvent($this));
		//publish context started logging event
		XEventContext::singleton()->publish(new XLoggingEvent($this, INFO, "YaxFramework Application Context Started."));
		if($route){			
			//dispatch filters
			XFilterDispatcher::singleton()->doFilter(XServletRequest::singleton(), XServletResponse::singleton());
			//start router
			$router = XRouter::singleton();
			self::singleton()->setRouter($router);
			$router->start();
		}
	}
	
	public function close(){
		XEventContext::singleton()->publish(new XContextClosedEvent($this));
		XEventContext::singleton()->publish(new XLoggingEvent($this, INFO, "YaxFramework Application Context Closed."));
	}
	
	/** 
	 * @return XApplication
	 */		
	function setRouter(XRouter $router) {
		$this->router = $router;
		return $this;
	}

	/** 
	 * @return XRouter
	 */		
	function router() {
		return $this->router;
	}	
	
	private function _init(){		
		$this->_loadDir(XFRAMEWORK_DIR.DIRECTORY_SEPARATOR."core");
		$this->_loadModule(XFRAMEWORK_DIR.DIRECTORY_SEPARATOR.'module');
		$this->_loadPlugin(XFRAMEWORK_DIR.DIRECTORY_SEPARATOR.'plugin');
		$this->_loadProject(PROJECT_ROOT);
		$this->_loadModule(PROJECT_ROOT.DIRECTORY_SEPARATOR.'modules');
		$this->_loadPlugin(PROJECT_ROOT.DIRECTORY_SEPARATOR.'plugins');
		set_error_handler(array(new XBasicErrorHandler(), 'handle'), E_ALL);
		set_exception_handler(array(new XBasicExceptionHandler(), 'handle'));
		register_shutdown_function(array($this, 'close'));
	}
	
	private function _loadProject($dir){
		$root = new XFile($dir);
		$files = $root->listFiles();
		foreach($files as $file){
			if(in_array($file->getName(), array(
				'config',
				'controllers',
				'i18n',
				'tmp',
				'views',
				'modules',
				'plugins',))){
				continue;
			}
			if($file->isDirectory()){
				$this->_loadDir($file->getPath());
			}
		}		
	}
		
	private function _loadModule($dir){
		$this->_loadDir($dir);
	}
	
	private function _loadPlugin($dir){
		$root = new XFile($dir);
		$files = $root->listFiles();
		foreach($files as $file){
			$path = $file->getPath();
			if(!$file->isDirectory()
				|| !file_exists($path.DIRECTORY_SEPARATOR.'class.php')){
				continue;
			}
			$classes = @include($path.DIRECTORY_SEPARATOR.'class.php');
			if(!$classes 
				|| !isset($classes['class'])
				|| !is_array($classes['class'])){
				continue;
			}
			foreach($classes['class'] as $class){
				x_require($path.DIRECTORY_SEPARATOR.$class);
			}
			$this->_loadPlugin($path);
		}
	}
	
	private function _loadDir($dir){
		$root = new XFile($dir);
		$files = $root->listFiles();
		foreach($files as $file){
			if($file->isDirectory()){
				$this->_loadDir($file->getPath());
			}elseif($file->isFile() && preg_match("/\.php$/i", $file->getName())){
				$this->_loadFile($file->getPath(), $file->getName());
			}
		}
	}
	
	private function _loadFile($path, $file){
		$className = x_class_name($file);
		if(class_exists($className, false)
			|| interface_exists($className, false)){
			return;
		}
		x_require($path);
		if(class_exists($className, false)){
			XAnnotationClassRegister::singleton()->register($className);
		}
	}
	
}
?>